// -------------------------------------------------
// BlinKit - BlinKit Library
// -------------------------------------------------
//   File Name: qjs_select_element.cpp
// Description: Bindings for HTMLSelectElement
//      Author: Ziming Li
//     Created: 2022-05-06
// -------------------------------------------------
// Copyright (C) 2022 MingYang Software Technology.
// -------------------------------------------------

#include "./qjs_bindings.h"

#include "blinkit/blink/renderer/bindings/core/qjs/qjs.h"
#include "blinkit/blink/renderer/bindings/core/qjs/qjs_c_function_list_entries.h"
#include "blinkit/blink/renderer/bindings/core/script_controller.h"
#include "blinkit/blink/renderer/core/HTMLNames.h"
#include "blinkit/blink/renderer/core/html/HTMLSelectElement.h"

/**
 * https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement
 */

using namespace blink::HTMLNames;

namespace BlinKit {
namespace qjs {

static JSValue GetDisabled(JSContext *ctx, JSValueConst thisVal)
{
    HTMLSelectElement *select = ScriptWrappable::Cast<HTMLSelectElement>(thisVal);
    return JS_NewBool(ctx, select->fastHasAttribute(disabledAttr));
}

static JSValue GetOptions(JSContext *ctx, JSValueConst thisVal)
{
    HTMLSelectElement *select = ScriptWrappable::Cast<HTMLSelectElement>(thisVal);

    GCRefPtr<HTMLCollection> ret = select->options();
    return ScriptController::From(ctx)->Wrap(ret.get());
}

static JSValue GetSelectedIndex(JSContext *ctx, JSValueConst thisVal)
{
    HTMLSelectElement *select = ScriptWrappable::Cast<HTMLSelectElement>(thisVal);
    return JS_NewInt32(ctx, select->selectedIndex());
}

static JSValue GetSelectedOptions(JSContext *ctx, JSValueConst thisVal)
{
    HTMLSelectElement *select = ScriptWrappable::Cast<HTMLSelectElement>(thisVal);

    GCRefPtr<HTMLCollection> ret = select->selectedOptions();
    return ScriptController::From(ctx)->Wrap(ret.get());
}

static JSValue GetSize(JSContext *ctx, JSValueConst thisVal)
{
    HTMLSelectElement *select = ScriptWrappable::Cast<HTMLSelectElement>(thisVal);
    return JS_NewInt32(ctx, select->size());
}

static JSValue GetValue(JSContext *ctx, JSValueConst thisVal)
{
    HTMLSelectElement *select = ScriptWrappable::Cast<HTMLSelectElement>(thisVal);
    return WrapString(ctx, select->value());
}

static JSValue SetDisabled(JSContext *ctx, JSValueConst thisVal, JSValueConst disabled)
{
    HTMLSelectElement *select = ScriptWrappable::Cast<HTMLSelectElement>(thisVal);
    select->setBooleanAttribute(disabledAttr, JS_ToBool(ctx, disabled));
    return JS_NewBool(ctx, select->fastHasAttribute(disabledAttr));
}

static JSValue SetSelectedIndex(JSContext *ctx, JSValueConst thisVal, JSValueConst selectedIndex)
{
    HTMLSelectElement *select = ScriptWrappable::Cast<HTMLSelectElement>(thisVal);

    int32_t index;
    JS_ToInt32(ctx, &index, selectedIndex);

    select->setSelectedIndex(index);
    return JS_NewInt32(ctx, select->selectedIndex());
}

static JSValue SetSize(JSContext *ctx, JSValueConst thisVal, JSValueConst size)
{
    HTMLSelectElement *select = ScriptWrappable::Cast<HTMLSelectElement>(thisVal);

    uint32_t s;
    JS_ToUint32(ctx, &s, size);

    select->setSize(s);
    return JS_NewUint32(ctx, select->size());
}

static JSValue SetValue(JSContext *ctx, JSValueConst thisVal, JSValueConst value)
{
    HTMLSelectElement *select = ScriptWrappable::Cast<HTMLSelectElement>(thisVal);

    select->setValue(ToAtomicString(ctx, value));
    return WrapString(ctx, select->value());
}

JSValue CreateSelectElementPrototype(JSContext *ctx, JSValue elementPrototype)
{
    static const JSCFunctionListEntry Funcs[] = {
        CGetSetEntry(Strings::Disabled, GetDisabled, SetDisabled),
        CGetSetEntry("options", GetOptions, nullptr),
        CGetSetEntry("selectedIndex", GetSelectedIndex, SetSelectedIndex),
        CGetSetEntry("selectedOptions", GetSelectedOptions, nullptr),
        CGetSetEntry(Strings::Size, GetSize, SetSize),
        CGetSetEntry(Strings::Value, GetValue, SetValue)
    };

    JSValue ret = JS_NewObjectProto(ctx, elementPrototype);
    JS_SetPropertyFunctionList(ctx, ret, Funcs, std::size(Funcs));
    return ret;
}

} // namespace qjs
} // namespace BlinKit
